import("//compiler-rt/target.gni")

source_set("cxx_sources") {
  configs -= [ "//llvm/utils/gn/build:llvm_code" ]
  configs += [ "//llvm/utils/gn/build:crt_code" ]
  sources = [ "rtl/tsan_new_delete.cpp" ]
}

if (current_os == "mac") {
  tsan_target_type = "shared_library"
} else {
  tsan_target_type = "static_library"
}

target(tsan_target_type, "tsan") {
  configs -= [ "//llvm/utils/gn/build:llvm_code" ]
  configs += [ "//llvm/utils/gn/build:crt_code" ]

  output_dir = crt_current_out_dir
  if (current_os == "mac") {
    output_name = "clang_rt.tsan_osx_dynamic"
  } else {
    assert(current_os != "win", "Tsan does not work on Windows")
    output_name = "clang_rt.tsan$crt_current_target_suffix"
  }

  deps = [
    "//compiler-rt/lib/interception:sources",
    "//compiler-rt/lib/sanitizer_common:sources",
    "//compiler-rt/lib/ubsan:sources",
  ]

  if (tsan_target_type == "static_library") {
    complete_static_lib = true
    configs -= [ "//llvm/utils/gn/build:thin_archive" ]
    deps += [ ":tsan_cxx" ]
  } else {
    deps += [
      ":cxx_sources",
      "//compiler-rt/lib/ubsan:cxx_sources",
    ]
  }

  # It's performance-critical for TSan runtime to be built with -fPIE to reduce
  # the number of register spills.
  cflags = [ "-fPIE" ]

  sources = [
    "rtl/tsan_clock.cpp",
    "rtl/tsan_clock.h",
    "rtl/tsan_debugging.cpp",
    "rtl/tsan_defs.h",
    "rtl/tsan_dense_alloc.h",
    "rtl/tsan_external.cpp",
    "rtl/tsan_fd.cpp",
    "rtl/tsan_fd.h",
    "rtl/tsan_flags.cpp",
    "rtl/tsan_flags.h",
    "rtl/tsan_flags.inc",
    "rtl/tsan_ignoreset.cpp",
    "rtl/tsan_ignoreset.h",
    "rtl/tsan_ilist.h",
    "rtl/tsan_interceptors.h",
    "rtl/tsan_interceptors_posix.cpp",
    "rtl/tsan_interface.cpp",
    "rtl/tsan_interface.h",
    "rtl/tsan_interface.inc",
    "rtl/tsan_interface_ann.cpp",
    "rtl/tsan_interface_ann.h",
    "rtl/tsan_interface_atomic.cpp",
    "rtl/tsan_interface_java.cpp",
    "rtl/tsan_interface_java.h",
    "rtl/tsan_malloc_mac.cpp",
    "rtl/tsan_md5.cpp",
    "rtl/tsan_mman.cpp",
    "rtl/tsan_mman.h",
    "rtl/tsan_mutexset.cpp",
    "rtl/tsan_mutexset.h",
    "rtl/tsan_platform.h",
    "rtl/tsan_ppc_regs.h",
    "rtl/tsan_preinit.cpp",
    "rtl/tsan_report.cpp",
    "rtl/tsan_report.h",
    "rtl/tsan_rtl.cpp",
    "rtl/tsan_rtl.h",
    "rtl/tsan_rtl_mutex.cpp",
    "rtl/tsan_rtl_proc.cpp",
    "rtl/tsan_rtl_report.cpp",
    "rtl/tsan_rtl_thread.cpp",
    "rtl/tsan_stack_trace.cpp",
    "rtl/tsan_stack_trace.h",
    "rtl/tsan_suppressions.cpp",
    "rtl/tsan_suppressions.h",
    "rtl/tsan_symbolize.cpp",
    "rtl/tsan_symbolize.h",
    "rtl/tsan_sync.cpp",
    "rtl/tsan_sync.h",
    "rtl/tsan_trace.h",
    "rtl/tsan_update_shadow_word.inc",
    "rtl/tsan_vector_clock.cpp",
    "rtl/tsan_vector_clock.h",
  ]
  if (target_os == "mac") {
    sources += [
      "rtl/tsan_interceptors_libdispatch.cpp",
      "rtl/tsan_interceptors_mac.cpp",
      "rtl/tsan_interceptors_mach_vm.cpp",
      "rtl/tsan_platform_mac.cpp",
      "rtl/tsan_platform_posix.cpp",
    ]
    cflags += [ "-fblocks" ]
  } else {
    # Assume Linux
    sources += [
      "rtl/tsan_platform_linux.cpp",
      "rtl/tsan_platform_posix.cpp",
    ]
  }
  if (target_cpu == "x64") {
    sources += [ "rtl/tsan_rtl_amd64.S" ]
  } else if (target_cpu == "arm64") {
    sources += [ "rtl/tsan_rtl_aarch64.S" ]
  } else if (target_cpu == "powerpc64") {
    sources += [ "rtl/tsan_rtl_ppc64.S" ]
  } else if (target_cpu == "mips64") {
    sources += [ "rtl/tsan_rtl_mips64.S" ]
  } else if (target_cpu == "s390x") {
    sources += [ "rtl/tsan_rtl_s390x.S" ]
  }

  # To be able to include sanitizer_common.
  include_dirs = [ ".." ]

  # FIXME: have SANITIZER_COMMON_CFLAGS thingy? should fno-builtin be in
  # crt_code?
  cflags += [ "-fno-builtin" ]

  # FIXME: link rt dl m pthread log
  # FIXME: dep on libcxx-headers?
  # FIXME: add_sanitizer_rt_version_list (cf hwasan)
  # FIXME: need libclang_rt.tsan*.a.syms?
  # FIXME: tsan_ignorelist.txt

  if (target_os == "mac") {
    # The -U flags below correspond to the add_weak_symbols() calls in CMake.
    ldflags = [
      "-lc++",
      "-lc++abi",
      "-lobjc",

      # sanitizer_common
      "-Wl,-U,___sanitizer_free_hook",
      "-Wl,-U,___sanitizer_malloc_hook",
      "-Wl,-U,___sanitizer_report_error_summary",
      "-Wl,-U,___sanitizer_sandbox_on_notify",
      "-Wl,-U,___sanitizer_symbolize_code",
      "-Wl,-U,___sanitizer_symbolize_data",
      "-Wl,-U,___sanitizer_symbolize_demangle",
      "-Wl,-U,___sanitizer_symbolize_flush",

      # FIXME: better
      "-Wl,-install_name,@rpath/libclang_rt.tsan_osx_dynamic.dylib",
    ]
    # FIXME: -Wl,-rpath
    # FIXME: codesign (??)
  }
}

if (tsan_target_type == "static_library") {
  static_library("tsan_cxx") {
    assert(current_os != "win", "FIXME")
    output_dir = crt_current_out_dir
    output_name = "clang_rt.tsan_cxx$crt_current_target_suffix"
    complete_static_lib = true
    configs -= [ "//llvm/utils/gn/build:thin_archive" ]
    deps = [
      ":cxx_sources",
      "//compiler-rt/lib/ubsan:cxx_sources",
    ]
  }
}
# FIXME:
# Build libcxx instrumented with TSan.
